package org.apache.commons.el;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import javax.servlet.jsp.el.VariableResolver;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.FunctionMapper;

/**
 * 描绘一个操作符获取一个Map键值对的entry的值,索引值，属性值，或者一个对象的索引属性值的全过程。以下是此操作符的运算规则：
 * <ul><pre>
 * 求a[b]的值 (假设 a.b == a["b"])
 *   如果a为null
 *     返回 null
 *   如果b为null
 *     返回 null
 *   如果a是一个Map集合
 *     假设!a.containsKey (b)成立
 *       则返回 null
 *     如果a.get(b) == null成立
 *       返回 null
 *     否则
 *       返回 a.get(b)
 *   如果a是一个List集合或者一个数组
 *     则(使用强制转换规则)把b强行转换成一个int数据类型 
 *     如果强行转换失败就报错
 *     如果调用a.get(b) 或 Array.get(a, b)的过程中引发ArrayIndexOutOfBoundsException 或 IndexOutOfBoundsException异常
 *       就返回null
 *     如果调用a.get(b) 或 Array.get(a, b)的过程中引发其他类型的异常,就报告错误
 *     如果执行以上条件都不成立就返回a.get(b) 或 Array.get(a, b)
 * 
 *   将b强制转换成String类型
 *	 假设b是一个可读属性getter,如果访问b的过程中引发异常,就报告错误
 *     否则 返回调用getter返回的结果
 *
 *   否则就报错
 * </pre></ul>
 * 
 * @author Nathan Abramson - Art Technology Group
 * @author Shawn Bayern
 * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: luehe $
 **/

public class ArraySuffix extends ValueSuffix {
	//-------------------------------------
	// 常量
	//-------------------------------------

	// 无参数组
	static Object[] sNoArgs = new Object[0];

	//-------------------------------------
	// 属性
	//-------------------------------------
	// 属性索引

	Expression mIndex;

	public Expression getIndex() {
		return mIndex;
	}

	public void setIndex(Expression pIndex) {
		mIndex = pIndex;
	}

	//-------------------------------------
	/**
	 *
	 * 构造函数
	 **/
	public ArraySuffix(Expression pIndex) {
		mIndex = pIndex;
	}

	//-------------------------------------
	/**
	 *
	 * 获取索引的值
	 **/
	Object evaluateIndex(VariableResolver pResolver, FunctionMapper functions,
			Logger pLogger) throws ELException {
		return mIndex.evaluate(pResolver, functions, pLogger);
	}

	//-------------------------------------
	/**
	 *
	 * 返回代表此操作符的标签
	 **/
	String getOperatorSymbol() {
		return "[]";
	}

	//-------------------------------------
	// 重写了类ValueSuffix中的方法 
	//-------------------------------------
	/**
	 *
	 * Returns the expression in the expression language syntax
	 **/
	public String getExpressionString() {
		return "[" + mIndex.getExpressionString() + "]";
	}

	//-------------------------------------
	/**
	 *
	 * Evaluates the expression in the given context, operating on the
	 * given value.
	 **/
	public Object evaluate(Object pValue, VariableResolver pResolver,
			FunctionMapper functions, Logger pLogger) throws ELException {
		Object indexVal;
		String indexStr;
		BeanInfoProperty property;
		BeanInfoIndexedProperty ixproperty;

		// 判断pValue的值是否为null
		if (pValue == null) {
			if (pLogger.isLoggingWarning()) {
				pLogger.logWarning(Constants.CANT_GET_INDEXED_VALUE_OF_NULL,
						getOperatorSymbol());
			}
			return null;
		}

		// 计算索引值
		else if ((indexVal = evaluateIndex(pResolver, functions, pLogger)) == null) {
			if (pLogger.isLoggingWarning()) {
				pLogger.logWarning(Constants.CANT_GET_NULL_INDEX,
						getOperatorSymbol());
			}
			return null;
		}

		// 判断pValue是不是一个Map集合
		else if (pValue instanceof Map) {
			Map val = (Map) pValue;
			return val.get(indexVal);
		}

		// 判断pValue是不是一个List集合或一个数组
		else if (pValue instanceof List || pValue.getClass().isArray()) {
			Integer indexObj = Coercions.coerceToInteger(indexVal, pLogger);
			if (indexObj == null) {
				if (pLogger.isLoggingError()) {
					pLogger.logError(Constants.BAD_INDEX_VALUE,
							getOperatorSymbol(), indexVal.getClass().getName());
				}
				return null;
			} else if (pValue instanceof List) {
				try {
					return ((List) pValue).get(indexObj.intValue());
				} catch (ArrayIndexOutOfBoundsException exc) {
					if (pLogger.isLoggingWarning()) {
						pLogger.logWarning(Constants.EXCEPTION_ACCESSING_LIST,
								exc, indexObj);
					}
					return null;
				} catch (IndexOutOfBoundsException exc) {
					if (pLogger.isLoggingWarning()) {
						pLogger.logWarning(Constants.EXCEPTION_ACCESSING_LIST,
								exc, indexObj);
					}
					return null;
				} catch (Exception exc) {
					if (pLogger.isLoggingError()) {
						pLogger.logError(Constants.EXCEPTION_ACCESSING_LIST,
								exc, indexObj);
					}
					return null;
				}
			} else {
				try {
					return Array.get(pValue, indexObj.intValue());
				} catch (ArrayIndexOutOfBoundsException exc) {
					if (pLogger.isLoggingWarning()) {
						pLogger.logWarning(Constants.EXCEPTION_ACCESSING_ARRAY,
								exc, indexObj);
					}
					return null;
				} catch (IndexOutOfBoundsException exc) {
					if (pLogger.isLoggingWarning()) {
						pLogger.logWarning(Constants.EXCEPTION_ACCESSING_ARRAY,
								exc, indexObj);
					}
					return null;
				} catch (Exception exc) {
					if (pLogger.isLoggingError()) {
						pLogger.logError(Constants.EXCEPTION_ACCESSING_ARRAY,
								exc, indexObj);
					}
					return null;
				}
			}
		}

		// Coerce to a String for property access

		else if ((indexStr = Coercions.coerceToString(indexVal, pLogger)) == null) {
			return null;
		}

		//从JavaBean属性中查找
		else if ((property = BeanInfoManager.getBeanInfoProperty(pValue
				.getClass(), indexStr, pLogger)) != null
				&& property.getReadMethod() != null) {
			try {
				return property.getReadMethod().invoke(pValue, sNoArgs);
			} catch (InvocationTargetException exc) {
				if (pLogger.isLoggingError()) {
					pLogger.logError(Constants.ERROR_GETTING_PROPERTY, exc
							.getTargetException(), indexStr, pValue.getClass()
							.getName());
				}
				return null;
			} catch (Exception exc) {
				if (pLogger.isLoggingError()) {
					pLogger.logError(Constants.ERROR_GETTING_PROPERTY, exc,
							indexStr, pValue.getClass().getName());
				}
				return null;
			}
		}

		else {
			if (pLogger.isLoggingError()) {
				pLogger.logError(Constants.CANT_FIND_INDEX, indexVal, pValue
						.getClass().getName(), getOperatorSymbol());
			}
			return null;
		}
	}

	//-------------------------------------
}
